//
//  LevelAdapter.m
//  CandyCrushClone
//
//  Created by Petar on 1/10/15.
//  Copyright (c) 2015 Nestorov Engineering. All rights reserved.
//

#import "LevelAdapter.h"
#import "CommunicationManager.h"
#import "Globals.h"
#import "GameInfo.h"

@implementation LevelAdapter
{
    NSMutableArray *_waveObjects;
    NSSet *_initialCookies;
}


+ (instancetype)sharedAdapter
{
    
    static LevelAdapter *mySharedAdapter = nil;
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        mySharedAdapter = [[self alloc] init];
    });
    
    return mySharedAdapter;
    
}


- (instancetype)init
{
    self = [super init];
    if (self) {
        
        _initialCookies = [NSSet new];
        
    }
    return self;
}


-(void)initGameWithBoard:(SFSObject *)params
{
    
    // reset Player cookie counters
    [[GameInfo sharedInfo].localPlayer resetCounters];
    [[GameInfo sharedInfo].otherPlayer resetCounters];
    
    // reset GameInfo params
    [GameInfo sharedInfo].isGameOver = NO;
    [GameInfo sharedInfo].winnerID = 0;
    
    SFSArray *initialCookiesSFSArray = [params getSFSArray:COOKIES_SET];
    
    NSSet *cookiesSet = [self parseCookiesSet:initialCookiesSFSArray];
    
    [self parseGameConditions:params];
    
    _initialCookies = [NSSet setWithSet:cookiesSet];
    
    [_delegate setInitialCookies:_initialCookies];
    
}


- (void)parseGameConditions:(SFSObject *)params
{
    
    SFSArray *gameWinConditionsSFSArray = [params getSFSArray:GAME_WIN_CONDITIONS];
    NSDictionary *gameWinConditions = [self parseConditions:gameWinConditionsSFSArray];
    
    [GameInfo sharedInfo].gameWinConditions = gameWinConditions;
    [GameInfo sharedInfo].localPlayer.gameWinConditions = gameWinConditions;
    [GameInfo sharedInfo].otherPlayer.gameWinConditions = gameWinConditions;
    
    NSLog(@"GameWinConditions: %@", gameWinConditions);
    
    // Get firstPlayer hero Usage conditions
    SFSObject *sfsFirstPlayerHeroUsageConditions = [params getSFSObject:FIRST_PLAYER_HERO_CONDITIONS];
    NSInteger firstPlayerId = [sfsFirstPlayerHeroUsageConditions getInt:PLAYER_ID];
    
    SFSArray *firstPlayerHeroConditionsSFSArray = [sfsFirstPlayerHeroUsageConditions getSFSArray:HERO_CONDITIONS];
    NSDictionary *firstPlayerHeroConditions = [self parseConditions:firstPlayerHeroConditionsSFSArray];
    
    // Get secondPlayer hero Usage conditions
    SFSObject *sfsSecondPlayerHeroUsageConditions = [params getSFSObject:SECOND_PLAYER_HERO_CONDITIONS];
    SFSArray *secondPlayerHeroConditionsSFSArray = [sfsSecondPlayerHeroUsageConditions getSFSArray:HERO_CONDITIONS];
    NSDictionary *secondPlayerHeroConditions = [self parseConditions:secondPlayerHeroConditionsSFSArray];
    
    // Get firstPlayer hero Skills
    SFSObject *sfsFirstPlayerHeroSkillsOnMyself = [params getSFSObject:FIRST_PLAYER_HERO_SKILLS_ON_MYSELF];
    SFSArray *firstPlayerHeroSkillsOnMyselfSFSArray = [sfsFirstPlayerHeroSkillsOnMyself getSFSArray:HERO_SKILLS_ON_MYSELF];
    NSDictionary *firstPlayerHeroSkillsOnMyself = [self parseConditions:firstPlayerHeroSkillsOnMyselfSFSArray];
    
    SFSObject *sfsFirstPlayerHeroSkillsOnOtherPlayer = [params getSFSObject:FIRST_PLAYER_HERO_SKILLS_ON_OTHER_PLAYER];
    SFSArray *firstPlayerHeroSkillsOnOtherPlayerSFSArray = [sfsFirstPlayerHeroSkillsOnOtherPlayer getSFSArray:HERO_SKILLS_ON_OTHER_PLAYER];
    NSDictionary *firstPlayerHeroSkillsOnOtherPlayer = [self parseConditions:firstPlayerHeroSkillsOnOtherPlayerSFSArray];

    // Get secondPlayer hero Skills
    SFSObject *sfsSecondPlayerHeroSkillsOnMyself = [params getSFSObject:SECOND_PLAYER_HERO_SKILLS_ON_MYSELF];
    SFSArray *secondPlayerHeroSkillsOnMyselfSFSArray = [sfsSecondPlayerHeroSkillsOnMyself getSFSArray:HERO_SKILLS_ON_MYSELF];
    NSDictionary *secondPlayerHeroSkillsOnMyself = [self parseConditions:secondPlayerHeroSkillsOnMyselfSFSArray];

    SFSObject *sfsSecondPlayerHeroSkillsOnOtherPlayer = [params getSFSObject:SECOND_PLAYER_HERO_SKILLS_ON_OTHER_PLAYER];
    SFSArray *secondPlayerHeroSkillsOnOtherPlayerSFSArray = [sfsSecondPlayerHeroSkillsOnOtherPlayer getSFSArray:HERO_SKILLS_ON_OTHER_PLAYER];
    NSDictionary *secondPlayerHeroSkillsOnOtherPlayer = [self parseConditions:secondPlayerHeroSkillsOnOtherPlayerSFSArray];
    
    [[GameInfo sharedInfo] setFirstPlayerHeroConditions:firstPlayerHeroConditions secondPlayerHeroConditions:secondPlayerHeroConditions firstPlayerHeroSkillsOnMyself:firstPlayerHeroSkillsOnMyself firstPlayerHeroSkillsOnOtherPlayer:firstPlayerHeroSkillsOnOtherPlayer secondPlayerHeroSkillsOnMyself:secondPlayerHeroSkillsOnMyself secondPlayerHeroSkillsOnOtherPlayer:secondPlayerHeroSkillsOnOtherPlayer withFirstPlayerId:firstPlayerId];
    
}


- (NSDictionary *)parseConditions:(SFSArray *)sfsConditions
{
    
    NSMutableDictionary *conditions = [NSMutableDictionary new];
    
    for (int i = 0; i < [sfsConditions size]; i++) {
        
        NSString *cookieTypeKey = [NSString stringWithFormat:@"%d",i+1];
        
        SFSObject *sfsCookieTypeValue = [sfsConditions getSFSObject:i];
        NSInteger cookieTypeValue = [sfsCookieTypeValue getInt:cookieTypeKey];
        
        [conditions addEntriesFromDictionary:@{ cookieTypeKey : @(cookieTypeValue) }];
        
    }
    
    return [NSDictionary dictionaryWithDictionary:conditions];
    
}

- (float)getAdditionalDelay:(SFSObject*)params
{
    
    SFSArray *movesParamsSFSArray = [params getSFSArray:MOVES_PARAMS];
    
    return [self parseMovesParams:movesParamsSFSArray].count * ADDITIONAL_DELAY_FOR_ONE_WAVE;
    
}


-(void)handleMoveResponse:(SFSObject *)params
{
    
    // get PLAYER_TO_MOVE playerID
    NSUInteger playerToMoveID = [params getInt:PLAYER_TO_MOVE];
    
    SFSArray *movesParamsSFSArray = [params getSFSArray:MOVES_PARAMS];
    
    // Array of Wave ( NSDictionary ) objects
    _waveObjects = [self parseMovesParams:movesParamsSFSArray];
    
    // get Swap Object
    SFSObject *swapSFSObject = [params getSFSObject:SWAP_OBJECT];
    RWTSwap *swap = [RWTSwap createSwapObjectFromSFSObject:swapSFSObject];
    
    // update PlayersInfo
    [self updatePlayersInfo:params];
    
    // check for Game Over
    [GameInfo sharedInfo].isGameOver = [params getBool:IS_GAME_OVER];
    [GameInfo sharedInfo].winnerID = [params getInt:WINNER_ID];
    
    // Parse Shuffle Cookies
    SFSArray *shuffleCookiesSFSArray = [params getSFSArray:SHUFFLE_COOKIES_SET];
    NSSet *shuffleCookiesSet = [self parseCookiesSet:shuffleCookiesSFSArray];
    
    if ( shuffleCookiesSet != nil ) {
        NSLog(@"Recieved Shuffle Cookies !!!");
        [GameInfo sharedInfo].shuffleCookiesSet = shuffleCookiesSet;
    }
    
    // Parse current Cookies
    SFSArray *currentBoardCookiesSFSArray = [params getSFSArray:CURRENT_COOKIES_SET];
    NSSet *currentBoardCookiesSet = [self parseCookiesSet:currentBoardCookiesSFSArray];
    [GameInfo sharedInfo].currentBoardCookiesSet = currentBoardCookiesSet;
    
    if ( [GameInfo sharedInfo].localPlayer.playerId == playerToMoveID ) {
        
        // Received Opponent move, post notification to execute it
        [[NSNotificationCenter defaultCenter] postNotificationName:PERFORM_SWAP object:self userInfo:@{ @"swap" : swap }];
        
        [[GameInfo sharedInfo] setIsMyTurn:YES];
        
    } else {
        
        // Received mine move, post notification to continue execution of mine move if there was Lag
        [[NSNotificationCenter defaultCenter] postNotificationName:RECEIVED_RESPONSE object:nil];
        NSLog(@"Received mine SWAP from Server!");
        
    }
    
}


-(NSMutableArray *)parseMovesParams:(SFSArray *)movesParamsSFSArray
{
    
    NSMutableArray *waveObjects = [NSMutableArray array];
    
    NSLog(@"Number of Waves: %ld", (long)[movesParamsSFSArray size]);
    
    // Parse Wave objects
    for (int i = 0; i < [movesParamsSFSArray size]; i++) {
        
        SFSObject *currentWaveObject = [movesParamsSFSArray getSFSObject:i];
        
        // get FillHolesArray
        SFSArray *fillHolesSFSArray = [currentWaveObject getSFSArray:FILL_HOLES_COOKIES];
        NSArray *fillHolesCookies = [self getNSArrayFromSFSArray:fillHolesSFSArray];
        
        // get TopUpCookiesArray
        SFSArray *topUpSFSArray = [currentWaveObject getSFSArray:TOP_UP_COOKIES];
        NSArray *topUpCookies = [self getNSArrayFromSFSArray:topUpSFSArray];
        
        // get HeroWaveInfo
        SFSObject *sfsHeroWaveInfo = [currentWaveObject getSFSObject:HERO_WAVE_INFO];
        NSDictionary *heroWaveInfo = @{ HERO_TYPE       : @([sfsHeroWaveInfo getInt:HERO_TYPE]),
                                        SHOULD_USE_HERO : @([sfsHeroWaveInfo getBool:SHOULD_USE_HERO]) };
        
//        NSLog(@"heroWaveInfo: %@",heroWaveInfo);
        
        NSDictionary *wave = @{ FILL_HOLES_COOKIES : fillHolesCookies,
                                TOP_UP_COOKIES : topUpCookies,
                                HERO_WAVE_INFO : heroWaveInfo };
        
        [waveObjects addObject:wave];
    }
    
    return [NSMutableArray arrayWithArray:waveObjects];
    
}


// Helper method to parse SFSArray with SFSArrays inside of it, to NSArray of NSArray with RWTCookies
-(NSArray *)getNSArrayFromSFSArray:(SFSArray *)sfsArray
{
    
    NSMutableArray *outerNSArray = [NSMutableArray array];
    
    for (int i = 0; i < [sfsArray size]; i++) {
        
        SFSArray *innerSFSArray = [sfsArray getSFSArray:i];
        
        NSMutableArray *innerArray = [NSMutableArray array];
        
        for (int k = 0; k < [innerSFSArray size]; k++) {
            
            SFSObject *sfsCookie = [innerSFSArray getSFSObject:k];
            RWTCookie *cookie = [RWTCookie createCookieFromSFSObect:sfsCookie];
            [innerArray addObject:cookie];
            
        }
        
        [outerNSArray addObject:innerArray];
        
    }
    
    return [NSArray arrayWithArray:outerNSArray];
    
}


/*
 *  Set PlayersInfo for both players from server
 */
-(void)updatePlayersInfo:(SFSObject *)params
{
    
    NSArray *firstPlayerInfo = [self parseSFSArrayToNSArray:[params getSFSArray:FIRST_PLAYER_INFO]];
    NSArray *secondPlayerInfo = [self parseSFSArrayToNSArray:[params getSFSArray:SECOND_PLAYER_INFO]];
    
    // get HeroInfo for both players
    NSArray *firstPlayerHeroInfo = [self parseSFSArrayToNSArray:[params getSFSArray:FIRST_PLAYER_HERO_INFO]];
    NSArray *secondPlayerHeroInfo = [self parseSFSArrayToNSArray:[params getSFSArray:SECOND_PLAYER_HERO_INFO]];
    
    // LocalPlayer is FirstPlayer
    if ( [firstPlayerInfo[0] isEqual:@([GameInfo sharedInfo].localPlayer.playerId)] ) {
        
        [self setPlayersInfoFromServerForLocalPlayer:firstPlayerInfo localPlayerHero:firstPlayerHeroInfo otherPlayerInfo:secondPlayerInfo otherPlayerHero:secondPlayerHeroInfo];
        
    } else {
        
        // LocalPlayer is SecondPlayer
        [self setPlayersInfoFromServerForLocalPlayer:secondPlayerInfo localPlayerHero:secondPlayerHeroInfo otherPlayerInfo:firstPlayerInfo otherPlayerHero:firstPlayerHeroInfo];
        
    }
    
}


- (void)setPlayersInfoFromServerForLocalPlayer:(NSArray*)localPlayerInfo localPlayerHero:(NSArray*)localPlayerHeroInfo otherPlayerInfo:(NSArray*)otherPlayerInfo otherPlayerHero:(NSArray*) otherPlayerHeroInfo
{
    
    [GameInfo sharedInfo].localPlayer.playerInfoFromServer = localPlayerInfo;
    [GameInfo sharedInfo].localPlayer.hero.heroInfoFromServer = localPlayerHeroInfo;
    
    [GameInfo sharedInfo].otherPlayer.playerInfoFromServer = otherPlayerInfo;
    [GameInfo sharedInfo].otherPlayer.hero.heroInfoFromServer = otherPlayerHeroInfo;
    
//    NSLog(@"localPlayerInfo: %@",localPlayerInfo);
//    NSLog(@"otherPlayerInfo: %@",otherPlayerInfo);
    
}

/*
 *  Get PlayersInfo as NSArray from SFSArray
 */
-(NSArray *)parseSFSArrayToNSArray:(SFSArray *)sfsArray
{
    
    NSMutableArray *mutableArray = [NSMutableArray array];
    
    for (int i = 0; i < [sfsArray size]; i++) {
        [mutableArray addObject:@([sfsArray getInt:i])];
    }
    
    return [NSArray arrayWithArray:mutableArray];
    
}


-(NSArray *)getTopUpCookies
{
    
    NSArray *topUpCookies = nil;
    
    if ( _waveObjects.count > 0 ) {
        
        // there is TUC from server
        NSDictionary *wave = _waveObjects.firstObject;
        topUpCookies = wave[TOP_UP_COOKIES];
        
        [self updateGameInfoForWave:wave];
        
        // remove the Wave object from the Array of Waves
        [_waveObjects removeObjectAtIndex:0];
        
    }
    
    return topUpCookies;
    
}


- (void)updateGameInfoForWave:(NSDictionary *)currentWave
{
    
    GameInfo *gameInfo = [GameInfo sharedInfo];
    
    NSDictionary *heroWaveInfo = currentWave[HERO_WAVE_INFO];
    gameInfo.shouldUseHero = [heroWaveInfo[SHOULD_USE_HERO] boolValue];
    
}


- (NSSet *)parseCookiesSet:(SFSArray *)sfsCookies
{
    
    if ( sfsCookies == nil  ) return nil;
    
    NSMutableSet *cookiesSet = [NSMutableSet new];
    
    for (int i = 0; i < [sfsCookies size]; i++) {
        
        SFSObject *cookieSFSObj = [sfsCookies getSFSObject:i];
        RWTCookie *cookie = [RWTCookie createCookieFromSFSObect:cookieSFSObj];
        
        [cookiesSet addObject:cookie];
        
    }

    return cookiesSet;
    
}


- (void)handleForcedGameOverResponse:(SFSObject *)params
{
    
    // check for Game Over
    [GameInfo sharedInfo].isGameOver = [params getBool:IS_GAME_OVER];
    [GameInfo sharedInfo].winnerID = [params getInt:WINNER_ID];
    
    // Received FORCED_GAME_OVER, so post notification to RWTViewController to show Game Over screen
    [[NSNotificationCenter defaultCenter] postNotificationName:CMD_FORCED_GAME_OVER object:nil];
    NSLog(@"Received CMD_FORCED_GAME_OVER from Server!");
    
}


- (void)resetParameters
{
    
    _waveObjects = [NSMutableArray new];
    _initialCookies = [NSSet new];
    
}


- (void)handleGetStoreInfo:(SFSObject*)params
{
    
    SFSArray *purchasesRewardsSFSArray = [params getSFSArray:STORE_PURCHASES_REWARDS];
    SFSArray *upgradePricesSFSArray = [params getSFSArray:STORE_UPGRADE_PRICES];
    
    NSArray *purchasesRewardsArray = [self parseSFSArrayToNSArray:purchasesRewardsSFSArray];
    NSArray *upgradePricesArray = [self parseSFSArrayToNSArray:upgradePricesSFSArray];
    
    NSDictionary *userInfo = @{ STORE_PURCHASES_REWARDS : purchasesRewardsArray,
                                STORE_UPGRADE_PRICES : upgradePricesArray };
    
    [[NSNotificationCenter defaultCenter] postNotificationName:CMD_GET_STORE_INFO
                                                        object:nil
                                                      userInfo:userInfo];
    
}


@end
